package com.rupertjones.globalcron.domain.audit;

import com.rupertjones.globalcron.domain.AuditLog;
import com.rupertjones.globalcron.domain.AuditLogType;
import com.rupertjones.globalcron.domain.BaseEntity;
import com.rupertjones.globalcron.domain.dao.AuditLogDAO;
import com.rupertjones.globalcron.domain.dao.PostPersistenceEventListener;
import com.rupertjones.globalcron.domain.dao.SessionContextProvider;
import com.rupertjones.globalcron.domain.dao.SystemSessionContextProvider;
import org.apache.log4j.Logger;
import org.hibernate.event.PostDeleteEvent;
import org.hibernate.event.PostInsertEvent;
import org.hibernate.event.PostUpdateEvent;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Date;

import static java.lang.String.format;

/**
 * <p>&copy Rupert Jones 2012</p>
 *
 * @author rup
 */
@Component
public class AuditLoggingPostPersistenceEventListener implements PostPersistenceEventListener {

    private static final Logger LOG = Logger.getLogger(PostPersistenceEventListener.class);

    private SessionContextProvider sessionContextProvider = new SystemSessionContextProvider();

    @Autowired
    private AuditLogDAO auditLogDAO;

    @Override
    public void onPostDelete(PostDeleteEvent event) {
    }

    @Override
    @SuppressWarnings("unchecked")
    public void onPostInsert(PostInsertEvent event) {
        Auditable entity = (Auditable) event.getEntity();
        AuditLogType type = entity.getAuditTypeForInsert();
        audit(entity, type);
    }

    @Override
    @SuppressWarnings("unchecked")
    public void onPostUpdate(PostUpdateEvent event) {
        Auditable entity = (Auditable) event.getEntity();
        AuditLogType type = entity.getAuditTypeForUpdate();
        audit(entity, type);
    }

    public void setSessionContextProvider(SessionContextProvider provider) {
        this.sessionContextProvider = provider;
    }

    @Override
    public boolean supports(Class<? extends BaseEntity> clazz) {
        return Auditable.class.isAssignableFrom(clazz);
    }

    private void audit(Auditable entity, AuditLogType type) {
        try {
            String user = sessionContextProvider.getCurrentUser();
            AuditLog log = new AuditLog();
            log.setType(type);
            log.setCreatedAt(new Date());
            log.setUser(user);
            log.setMessage(format("[Entity: %s] [Summary: %s] [by: %s]", entity.getClass().getName(), entity.toAuditLog(), user));
            auditLogDAO.upsert(log);
        } catch (Throwable th) {
            LOG.error("Audit Log could not be saved - actions are not recorded", th);
        }
    }
}
